package com.zdp.nio.channel.socketchannel.file;

import lombok.Builder;
import lombok.Data;
import lombok.SneakyThrows;
import sun.misc.IOUtils;
import sun.nio.ch.IOUtil;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.LongBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Objects;

/**
 * 客户端 Socket , 读取本地文件，将本地文件传输到服务端
 * 1. 先发送 目标文件名称（不带路径）
 * 2. 发送文件长度
 * 3。 发送文件内容
 */
@Data
public class SocketClient {

    @SneakyThrows
    public static void main(String[] args) {
        String sourceFile = SocketClient.class.getClassLoader().getResource("File.txt").getPath();
        String descFile = "Test.txt";
        SocketClient client = new SocketClient("127.0.0.1",9905,sourceFile,descFile);
        client.sendFile();
    }


    public SocketClient(String ip,Integer port,String sourceFile,String destFile){
        this.ip = ip;
        this.port = port;
        this.sourceFile = sourceFile;
        this.destFile = destFile;
    }
    private int port;
    private String ip;
    private String sourceFile;

    private String destFile;

    private Charset charset = Charset.forName("UTF-8");

    private ByteBuffer lengthBuffer = ByteBuffer.allocate(8);

    @SneakyThrows
    public void sendFile()   {
        File file = new File(sourceFile);
        if(!file.exists()){
            file.createNewFile();
        }
        FileInputStream inputStream = null;
        FileChannel fileChannel = null;

        SocketChannel socketChannel = null;
        try{
            // 1. 初始化文件通道
            inputStream = new FileInputStream(file);
            fileChannel = inputStream.getChannel();
            // 2. 初始化Socket
            socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(false);
            socketChannel.connect(new InetSocketAddress(ip,port));
            // 2.1 判断连接是否成功建立
            while(!socketChannel.finishConnect()){}
            System.out.println("Client成功连接服务器端");
            // 3. 发送文件名称
            ByteBuffer fileNameByByteBuffer = charset.encode(destFile);
            lengthBuffer.putLong(fileNameByByteBuffer.limit());
            lengthBuffer.flip();
            // 写入数据长度
            socketChannel.write(lengthBuffer);
            lengthBuffer.clear();
            while (fileNameByByteBuffer.hasRemaining()){
                socketChannel.write(fileNameByByteBuffer);
            }
            // 4. 发送文件长度
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            byteBuffer.putLong(file.length());
            System.out.println("文件长度 ： "  + file.length());
            byteBuffer.flip();
            // 写入数据长度
            lengthBuffer.putLong(byteBuffer.limit());
            lengthBuffer.flip();
            socketChannel.write(lengthBuffer);
            lengthBuffer.clear();
            while(byteBuffer.hasRemaining()){
                socketChannel.write(byteBuffer);
            }
            byteBuffer.clear();

            // 5. 发送文件内容
            System.out.println("开始传输文件");
            int length = 0;
            long progress = 0;
            lengthBuffer.putLong(file.length());
            lengthBuffer.flip();
            socketChannel.write(lengthBuffer);
            lengthBuffer.clear();
            while((length = fileChannel.read(byteBuffer)) > 0){
                byteBuffer.flip();
                while(byteBuffer.hasRemaining()){
                    socketChannel.write(byteBuffer);
                }
                byteBuffer.clear();
                progress += length;
                System.out.println("| " + (100 * progress / file.length()) +"%");
            }
            if(length == -1) {
                // 6. 通知结束
                socketChannel.shutdownOutput();
            }
            System.out.println("========== 文件传输成功 ============");
        }finally {
            if(Objects.nonNull(inputStream)){
                inputStream.close();
            }
            if(Objects.nonNull(fileChannel)){
                fileChannel.close();
            }
            if(Objects.nonNull(socketChannel)){
                socketChannel.close();
            }
        }

    }

}
